// Copyright 2019 The Go Authors. All rights reserved.
// Use of this session code is governed by a BSD-style
// license that can be found in the LICENSE file.

package lsp

import (
	"context"
	"mi/internal/lsp/protocol"
	"mi/internal/lsp/session"
	"mi/internal/xpath"
)

func (s *Server) documentSymbol(ctx context.Context, params *protocol.DocumentSymbolParams) ([]interface{}, error) {
	root, err := s.session.GetNavigationTree(ctx, xpath.URI(params.TextDocument.URI))
	if err != nil {
		return nil, err
	}
	
	return convertRootTree(params.TextDocument.URI, root), nil
}

func convertRootTree(resource protocol.DocumentURI, root *session.NavigationTree) []interface{} {
	var result []interface{}
	for _, item := range root.ChildItems {
		result = append(result, convertNavTree(resource, item))
	}
	return result
}

func convertNavTree(resource protocol.DocumentURI, item *session.NavigationTree) interface{} {
	var result = convertSymbol(item)
	for _, childItem := range item.ChildItems {
		result.Children = append(result.Children, convertSymbol(childItem))
	}
	return result
}

func convertSymbol(item *session.NavigationTree) protocol.DocumentSymbol {
	return protocol.DocumentSymbol{
		Name:  			item.Text,
		Detail:         "",
		Kind:           getSymbolKind(item.Kind),
		Tags:           nil,
		Deprecated:     false,
		Range:          toProtocolRange(item.Span),
		SelectionRange: toProtocolRange(item.Span),
		Children: make([]protocol.DocumentSymbol, 0),
	}
}

func getSymbolKind(kind session.ScriptElementKind) protocol.SymbolKind {
	switch kind {
	case session.SEKModuleElement:
		return protocol.Module
	case session.SEKClassElement:
		return protocol.Class
	case session.SEKEnumElement:
		return protocol.Enum
	case session.SEKInterfaceElement:
		return protocol.Interface
	case session.SEKMemberFunctionElement:
		return protocol.Method
	case session.SEKMemberVariableElement:
		return protocol.Property
	case session.SEKVariableElement:
		return protocol.Variable
	case session.SEKLocalVariableElement:
		return protocol.Variable
	case session.SEKFunctionElement:
		return protocol.Function
	case session.SEKLocalFunctionElement:
		return protocol.Function
	case session.SEKConstructSignatureElement:
		return protocol.Constructor
	case session.SEKConstructorImplementationElement:
		return protocol.Constructor
	}
	return protocol.Variable
}